<?php
namespace Core;
use Libs\FileLog;

defined('ENV') || exit('illegal Access! @110');
class Route
{
	public static $router = []; //所有路由
	public static $path = '';

	public static $isMatch = false; //是否匹配
	public static $PathMatchName = ''; //匹配的路由规则
	public static $PathMatchInfo = []; //匹配解析后的信息
	public static $PathMatchGroup = ''; //匹配的规则集名字

	public static $module = '';
	public static $controller = '';
	public static $action = '';

	public static $pathRouter = [];

	public static $args = [];

	public static $error = '';

	private function __construct()
	{}

	//匹配路由, 挨个读取路由文件, 每读取一个文件就匹配一次, 最差的情况是把所有的文件都读一遍
	public static function matchURI($path)
	{
		self::$path = $path = trim($path, '/');
		
		//1. uri为空, 走默认路由
		if (empty($path)) {
            self::$module     = DEFAULT_MODULE;
            self::$controller = DEFAULT_CONTROLLER;
            self::$action     = DEFAULT_ACTION;
            
			self::$isMatch = true;
            self::$PathMatchInfo = [self::$module, self::$controller, self::$action];
			self::$PathMatchGroup = 'default';
            return true;
        }

		//2. uri不为空
		//2.1先尝试按照斜线分割, 斜线前的部分决定了使用哪个路由文件, 后边的部分用来匹配具体路由
		$parse = explode('/', $path, 2);
		if (count($parse) == 2) {
			$file = $parse[0];
			$filePath = ROUTERPATH.$file.'.php';
			if (file_exists($filePath)) {
				self::$PathMatchGroup = $file;
				include($filePath);
				$ruler = $GLOBALS['router'][$file];
				return self::matchPath($ruler, $parse[1]);
			}
			return false;
		} 
		
		//2.2 读取路由缓存进行匹配
		if (file_exists(ROUTERPATH.'cache.php')) { 
			include(ROUTERPATH.'cache.php'); 
			foreach ($GLOBALS['router']['cache'] as $name => $rulers) {
				if (self::matchPath($rulers, $path)) {
					self::$PathMatchGroup = $name;
					return true;
				}
			}
			return false;
		}

		//2.3 读取所有路由文件, 每读入一个就进行匹配, 一旦匹配就不再读其他的路由文件了
		$files = scandir(ROUTERPATH);
		foreach ($files as $file) {
			$i = pathinfo($file); //$file有后缀
			$name = $i['filename'];
			$ext = $i['extension'];
			if ($ext != 'php') {
				continue;
			}

			include(ROUTERPATH.$file);
			if (self::matchPath($GLOBALS['router'][$name], $path)) {
				self::$PathMatchGroup = $name;
				return true;
			}
		}
		
		return false;
	}

	/**
	 * 匹配给定的规则集
	 * @param array $rulers 规则集
	 * @param string $path 访问路径
	 */
	public static function matchPath($rulers, $path)
	{
		if (self::wordMatch($rulers, $path)) { //全词匹配
			return true;
		} else if (self::pregMatch($rulers, $path)) { //正则匹配
			return true;
		} else if (self::wordMatch($rulers, 'default')) { //都没有匹配到, 就找到规则中的default去匹配
			return true;
		} else {
            return false;
        }
	}

	//全词匹配
	public static function wordMatch($rulers, $path)
	{
		if (isset($rulers[$path])) {
			self::$isMatch = true;
			self::$PathMatchName = $path;
            self::$PathMatchInfo = self::analysisPath($rulers[$path]);

			self::$module     = self::$PathMatchInfo['moduleName'];
			self::$controller = self::$PathMatchInfo['controllerName'];
			self::$action     = self::$PathMatchInfo['actionName'];
			self::$args       = self::$PathMatchInfo['args'];

			return true;
		}
		return false;
	}

	//正则匹配
	public static function pregMatch($rulers, $path)
	{
		foreach ($rulers as $pattern => $route) {
			//不是正则表达式就不用匹配了
			$isPattern = false;
			foreach (['(', '*', '[', '+', '?', '\\'] as $ch) {
				if (strpos($pattern, $ch) !== false) {
					$isPattern = true;
					break;
				}
			}
			if ($isPattern == false) {
				continue;
			}

			//正则匹配
			$countMatched = preg_match('#^'.$pattern.'$#', $path, $matches);
            //FileLog::info([$pattern, $path,$countMatched, $matches]);
			if ($countMatched == 0) {
				continue;
			}

			// "abc_123_456_789" => "$1/$2/$3/id/$4"
			// 变成 "abc/123/456/id/789"
			foreach ($matches as $key => $value) {
				$route = str_replace('$'.$key, $value, $route);
			}
            //FileLog::info($route);

			self::$isMatch = true;
			self::$PathMatchName = $pattern;
            self::$PathMatchInfo = self::analysisPath($route);
            //FileLog::info(self::$PathMatchInfo);
			self::$module     = self::$PathMatchInfo['moduleName'];
			self::$controller = self::$PathMatchInfo['controllerName'];
			self::$action     = self::$PathMatchInfo['actionName'];
			self::$args       = self::$PathMatchInfo['args'];
			
			return true;
		}
		
		return false;
	}

	//分析路径参数
	public static function analysisPath($path)
	{
        $moduleName     = DEFAULT_MODULE;
        $controllerName = DEFAULT_CONTROLLER;
        $actionName     = DEFAULT_ACTION;
	    $args = [];
	    
		//获得module/controller/action
		$arrPathInfo = explode('/', $path);//存放URL中以正斜线隔开的内容的数组
		!empty($arrPathInfo[0]) && ($moduleName = $arrPathInfo[0]);
		!empty($arrPathInfo[1]) && ($controllerName = $arrPathInfo[1]);
		!empty($arrPathInfo[2]) && ($actionName = $arrPathInfo[2]);

		//存放除module/controller/action之外的参数
		// /a/1/b/2/c/3 ==> ?a=1&b=2&c=3
		// 当键和值不成对出现时,默认最后一个键的值为0
		// 参数中不要出现数字键,否则在合并post,get参数时会出错
		if (count($arrPathInfo) > 3) {
			$arrPath = array_slice($arrPathInfo, 3);
			$intArgNum = count($arrPath);
			if ($intArgNum % 2 != 0) {
				$arrPath[] = '';//最后补一个''
			}

			for ($i=0; $i<$intArgNum; $i=$i+2) {
				$args[$arrPath[$i]] = $arrPath[$i+1];
			}
		}
		
		return array(
            'moduleName'     => $moduleName,
            'controllerName' => $controllerName,
            'actionName'     => $actionName,
            'args'           => $args
        );
	}

	public static function debug()
    {
        echo '<pre>';
        print_r([
            'isMatch' => self::$isMatch,
			'MatchGroup' => self::$PathMatchGroup,
            'MatchName' => self::$PathMatchName,
            'MatchInfo' => self::$PathMatchInfo,
        ]);
        exit();
    }

}
